import logger from '../../common/logger';
import _ from 'lodash';

import {
  JobFailedEvent,
  JobCreatedEvent,
  JobSucceedEvent,
  JobAssignedEvent,
  JobDispatchedEvent,
  JobIterruptedEvent
} from '../event';

import * as connectionManager from './connectionManager';

import { eventBus } from './eventBus';
import { JobScheduleService } from './scheduler/scheduleService';
import { SimluationDispatchService } from './dispatcher/dispatchService';
import { SimulationResultProcessor } from './jobResultProcessor';
import { JobRetryEvent } from '../event/jobRetry';

export class JobLifecycleManager {
  constructor(private scheduler: JobScheduleService, private dispatcher: SimluationDispatchService, private resultProcessor: SimulationResultProcessor) {
  }

  init() {
    eventBus.on(JobCreatedEvent.NAME, (e:JobCreatedEvent) => {
      const job = e.job;
      logger.info(`simulation job(id=${job.id}) created`);
      this.scheduler.schedule(job);
    });

    eventBus.on(JobAssignedEvent.NAME, (e:JobAssignedEvent) => {
      const job = e.job;
      logger.info(`simulation job(id=${job.id}) assigned to agent(identity=${job.agentId})`);
      this.dispatcher.dispatch(job);
    });

    eventBus.on(JobDispatchedEvent.NAME, (e: JobDispatchedEvent) => {
      const job = e.job;
      logger.info(`simulation job(id=${job.id}) dispatched to agent(identity=${job.agentId})`);
    });

    eventBus.on(JobSucceedEvent.NAME, (e: JobSucceedEvent) => {
      const job = e.job;
      logger.info(`simulation job(id=${job.id}) succeed result from agent(identity=${job.agentId})`);
      this.resultProcessor.handle(e.job);
    });

    eventBus.on(JobFailedEvent.NAME, (e: JobFailedEvent) => {
      const job = e.job;
      logger.info(`simulation job(id=${job.id}) failed result from agent(identity=${job.agentId})`);
      this.resultProcessor.handle(e.job);
    });

    eventBus.on(JobIterruptedEvent.NAME, (e: JobIterruptedEvent, modelBack : boolean = false) => {
      const job = e.job;
      logger.info(`simulation job(id=${job.id}) sends a termination signal to the agent`);
      const agentIdentity = job.agentId;
      const connection = connectionManager.getConnection(agentIdentity);

      if (connection) {
        logger.info(`jobId: ${job.id}, modelBack: ${modelBack}`);
        connection.emit('simulation:stop', { 'jobId': _.toString(job.id), 'modelBack': modelBack });
      } else {
        logger.info(`Agent(${agentIdentity}) not online. skip stop request.`);
      }
    });

    eventBus.on(JobRetryEvent.NAME, (e: JobRetryEvent) => {
      const job = e.job;
      logger.info(`simulation job(id=${job.id}) retry`);
      this.dispatcher.restart(job);
    });
  }
}